classdef CodeAnalysisService < handle
    % CODEANALYSISSERVICE 代码分析服务
    % 基于DO-178规则第4条（架构分离原则）设计
    % 负责协调所有代码分析相关的业务逻辑
    %
    % 功能：
    %   - 代码生成（genSrcCode）
    %   - 代码校验和计算（getCodeFileChecksum）
    %   - 代码检查（Code Inspector - verifySrcCode2Model）
    %   - Bug Finder分析（detectCodingErrs）
    %   - 编码标准检查（checkCodeStds）
    %   - Code Prover分析（proveCodeQuality）
    %   - 代码指标计算（computeCodeMetrics）
    %   - 批量代码分析（运行所有分析并收集结果）
    %
    % 设计原则：
    %   - 单一职责：只负责代码分析业务逻辑协调
    %   - 依赖注入：依赖现有的代码分析工具
    %   - 错误明确：遵循规则第2条，不使用silent fallback
    %   - 可测试：所有公共方法都可以独立测试
    %
    % 使用示例：
    %   % 获取单例实例（DEV环境）
    %   service = CodeAnalysisService.getInstance();
    %   
    %   % 获取单例实例（CI环境）
    %   service = CodeAnalysisService.getInstance('Environment', 'CI');
    %   
    %   % 生成代码
    %   result = service.generateCode('MyModel');
    %   result = service.generateCode('MyModel', 'TreatAsTopMdl');
    %   
    %   % 运行代码检查
    %   result = service.runCodeInspector('MyModel');
    %   result = service.runCodeInspector('MyModel', 'TreatAsTopMdl');
    %   
    %   % 运行Polyspace分析
    %   result = service.runBugFinder('MyModel');
    %   result = service.runCodeStandards('MyModel', 'TreatAsTopMdl');
    %   result = service.runCodeProver('MyModel', 'TreatAsTopMdl', 'IncludeAllChildMdls');
    %   
    %   % 计算代码指标
    %   result = service.computeCodeMetrics('MyModel');
    %   
    %   % 计算代码文件校验和
    %   result = service.getChecksum('CodeDir', 'D:\code\path');
    %   
    %   % 运行所有分析
    %   results = service.runAllAnalysis('MyModel');
    %   results = service.runAllAnalysis('MyModel', 'TreatAsTopMdl');
    %
    % 作者: MBD Platform Team
    % 日期: 2025-10-26
    % 最后修改: 2025-10-26
    % 遵循DO-178标准
    
    properties (Access = private)
        projectRoot         % 项目根目录
        analysisCache       % 分析结果缓存
        environment         % 运行环境：'DEV' 或 'CI'
        logger              % LoggingService实例
    end
    
    methods (Access = private)
        function obj = CodeAnalysisService(varargin)
            % 私有构造函数 - 初始化服务（单例模式）
            % 输入：
            %   'Environment' - 可选，运行环境 'DEV'（默认）或 'CI'
            % 基于规则第2条：不使用silent fallback，明确报告错误
            
            % 初始化日志服务
            try
                obj.logger = LoggingService.getInstance();
            catch ME
                warning('LoggingService:Unavailable', '日志服务不可用: %s', ME.message);
                obj.logger = [];
            end
            
            % 解析输入参数
            p = inputParser;
            addParameter(p, 'Environment', 'DEV', @(x) ismember(x, {'DEV', 'CI'}));
            parse(p, varargin{:});
            
            obj.environment = p.Results.Environment;
            obj.analysisCache = struct();
            
            try
                % 获取项目根目录
                obj.projectRoot = pwd;
                fprintf('✅ CodeAnalysisService已初始化\n');
                fprintf('   项目根目录: %s\n', obj.projectRoot);
                fprintf('   运行环境: %s\n', obj.environment);
                
                if ~isempty(obj.logger)
                    obj.logger.logInfo(sprintf('CodeAnalysisService已初始化 (环境: %s)', obj.environment));
                end
            catch ME
                if ~isempty(obj.logger)
                    obj.logger.logError(sprintf('代码分析服务初始化失败: %s', ME.message));
                end
                error('CodeAnalysisService:InitFailed', ...
                    '无法初始化代码分析服务：%s', ME.message);
            end
        end
    end
    
    methods (Static, Access = public)
        function obj = getInstance(varargin)
            % 获取CodeAnalysisService的单例实例
            % 输入：
            %   'Environment' - 可选，运行环境 'DEV'（默认）或 'CI'
            % 输出：
            %   obj - CodeAnalysisService单例实例
            
            persistent instance;
            
            if isempty(instance) || ~isvalid(instance)
                instance = CodeAnalysisService(varargin{:});
                fprintf('✅ 创建CodeAnalysisService单例实例\n');
            end
            
            obj = instance;
        end
    end
    
    methods (Access = public)
        
        %% ==================== 代码生成 ====================
        
        function result = generateCode(obj, modelName, varargin)
            % 生成模型代码
            % 输入：
            %   modelName - 模型名称
            %   varargin - 可选参数：'TreatAsTopMdl'
            % 输出：
            %   result - 包含成功标志和消息的结构体
            % 基于规则第2条：明确报告错误
            
            result = struct('success', false, 'message', '', 'codePath', '', 'details', struct());
            
            if nargin < 2 || isempty(modelName)
                error('CodeAnalysisService:InvalidInput', '模型名称不能为空');
            end
            
            try
                fprintf('🔨 正在为模型生成代码: %s\n', modelName);
                
                % 基于规则第4条：调用独立的代码生成工具函数
                codeGenResult = genSrcCode(modelName, varargin{:});
                
                result.success = true;
                result.message = codeGenResult.Message;
                result.details = codeGenResult;
                % 基于规则第4条：使用ProjectPathManager获取代码路径
                result.codePath = ProjectPathManager.getDirPath('code');
                
                fprintf('✅ 代码生成完成: %s\n', result.message);
                
            catch ME
                result.success = false;
                result.message = sprintf('代码生成失败: %s', ME.message);
                result.error = ME;
                error('CodeAnalysisService:GenerateCodeFailed', result.message);
            end
        end
        
        %% ==================== 代码校验和 ====================
        
        function result = getChecksum(obj, varargin)
            % 计算代码文件的校验和（用于DO-178C可追溯性）
            % 输入：
            %   varargin - 可选参数，传递给getCodeFileChecksum
            % 输出：
            %   result - 包含成功标志、消息和校验和数据的结构体
            % 基于规则第2条：明确报告错误
            
            result = struct('success', false, 'message', '', 'checksumData', struct());
            
            try
                fprintf('🔐 正在计算代码文件校验和...\n');
                
                % 基于规则第4条：调用独立的校验和计算工具函数
                checksumResult = getCodeFileChecksum(varargin{:});
                
                result.success = true;
                result.message = checksumResult.Message;
                result.checksumData = checksumResult;
                
                fprintf('✅ 代码文件校验和计算完成\n');
                
            catch ME
                result.success = false;
                result.message = sprintf('代码文件校验和计算失败: %s', ME.message);
                result.error = ME;
                error('CodeAnalysisService:GetChecksumFailed', result.message);
            end
        end
        
        %% ==================== 代码检查 ====================
        
        function result = runCodeInspector(obj, modelName, varargin)
            % 运行Simulink Code Inspector
            % 输入：
            %   modelName - 模型名称
            %   varargin - 可选参数：'TreatAsTopMdl', 'IncludeAllChildMdls'
            % 输出：
            %   result - 包含成功标志和消息的结构体
            
            result = struct('success', false, 'message', '', 'reportPath', '', 'details', struct());
            
            if nargin < 2 || isempty(modelName)
                error('CodeAnalysisService:InvalidInput', '模型名称不能为空');
            end
            
            try
                fprintf('🔍 正在运行Code Inspector: %s\n', modelName);
                
                % 基于规则第4条：调用独立的Code Inspector工具函数
                % 根据环境添加CI参数
                args = varargin;
                if strcmpi(obj.environment, 'CI')
                    args{end+1} = 'CI';
                end
                
                inspectorResult = verifySrcCode2Model(modelName, args{:});
                
                result.success = true;
                result.message = inspectorResult.Message;
                result.details = inspectorResult;
                result.reportPath = obj.getCodeInspectorReportPath(modelName);
                
                fprintf('✅ Code Inspector完成\n');
                
            catch ME
                result.success = false;
                result.message = sprintf('Code Inspector失败: %s', ME.message);
                result.error = ME;
                error('CodeAnalysisService:RunCodeInspectorFailed', result.message);
            end
        end
        
        %% ==================== Polyspace分析 ====================
        
        function result = runBugFinder(obj, modelName, varargin)
            % 运行Polyspace Bug Finder - 检测编码错误
            % 输入：
            %   modelName - 模型名称
            %   varargin - 可选参数：'TreatAsTopMdl'
            % 输出：
            %   result - 包含成功标志和消息的结构体
            
            result = struct('success', false, 'message', '', 'reportPath', '', 'details', struct());
            
            if nargin < 2 || isempty(modelName)
                error('CodeAnalysisService:InvalidInput', '模型名称不能为空');
            end
            
            try
                fprintf('🔬 正在运行Polyspace Bug Finder: %s\n', modelName);
                
                % 基于规则第4条：调用独立的Bug Finder工具函数
                % 根据环境添加CI参数
                args = varargin;
                if strcmpi(obj.environment, 'CI')
                    args{end+1} = 'CI';
                end
                
                bugFinderResult = detectCodingErrs(modelName, args{:});
                
                result.success = true;
                result.message = bugFinderResult.Message;
                result.details = bugFinderResult;
                result.reportPath = obj.getBugFinderReportPath(modelName);
                
                fprintf('✅ Bug Finder完成\n');
                
            catch ME
                result.success = false;
                result.message = sprintf('Bug Finder失败: %s', ME.message);
                result.error = ME;
                error('CodeAnalysisService:RunBugFinderFailed', result.message);
            end
        end
        
        function result = runCodeStandards(obj, modelName, varargin)
            % 运行Polyspace编码标准检查 - MISRA C等
            % 输入：
            %   modelName - 模型名称
            %   varargin - 可选参数：'TreatAsTopMdl'
            % 输出：
            %   result - 包含成功标志和消息的结构体
            
            result = struct('success', false, 'message', '', 'reportPath', '', 'details', struct());
            
            if nargin < 2 || isempty(modelName)
                error('CodeAnalysisService:InvalidInput', '模型名称不能为空');
            end
            
            try
                fprintf('📋 正在运行编码标准检查: %s\n', modelName);
                
                % 基于规则第4条：调用独立的编码标准检查工具函数
                % 根据环境添加CI参数
                args = varargin;
                if strcmpi(obj.environment, 'CI')
                    args{end+1} = 'CI';
                end
                
                codeStdsResult = checkCodeStds(modelName, args{:});
                
                result.success = true;
                result.message = codeStdsResult.Message;
                result.details = codeStdsResult;
                result.reportPath = obj.getCodeStandardsReportPath(modelName);
                
                fprintf('✅ 编码标准检查完成\n');
                
            catch ME
                result.success = false;
                result.message = sprintf('编码标准检查失败: %s', ME.message);
                result.error = ME;
                error('CodeAnalysisService:RunCodeStandardsFailed', result.message);
            end
        end
        
        function result = runCodeProver(obj, modelName, varargin)
            % 运行Polyspace Code Prover - 证明代码质量
            % 输入：
            %   modelName - 模型名称
            %   varargin - 可选参数：'TreatAsTopMdl', 'IncludeAllChildMdls'
            % 输出：
            %   result - 包含成功标志和消息的结构体
            
            result = struct('success', false, 'message', '', 'reportPath', '', 'details', struct());
            
            if nargin < 2 || isempty(modelName)
                error('CodeAnalysisService:InvalidInput', '模型名称不能为空');
            end
            
            try
                fprintf('🔐 正在运行Polyspace Code Prover: %s\n', modelName);
                
                % 基于规则第4条：调用独立的Code Prover工具函数
                % 根据环境添加CI参数
                args = varargin;
                if strcmpi(obj.environment, 'CI')
                    args{end+1} = 'CI';
                end
                
                codeProverResult = proveCodeQuality(modelName, args{:});
                
                result.success = true;
                result.message = codeProverResult.Message;
                result.details = codeProverResult;
                result.reportPath = obj.getCodeProverReportPath(modelName);
                
                fprintf('✅ Code Prover完成\n');
                
            catch ME
                result.success = false;
                result.message = sprintf('Code Prover失败: %s', ME.message);
                result.error = ME;
                error('CodeAnalysisService:RunCodeProverFailed', result.message);
            end
        end
        
        %% ==================== 代码指标 ====================
        
        function result = computeCodeMetrics(obj, modelName, varargin)
            % 计算代码质量指标
            % 输入：
            %   modelName - 模型名称
            %   varargin - 可选参数：'TreatAsTopMdl'
            % 输出：
            %   result - 包含成功标志、消息和指标的结构体
            
            result = struct('success', false, 'message', '', 'reportPath', '', 'details', struct());
            
            if nargin < 2 || isempty(modelName)
                error('CodeAnalysisService:InvalidInput', '模型名称不能为空');
            end
            
            if ~isempty(obj.logger)
                obj.logger.logInfo(sprintf('开始计算代码指标: %s', modelName));
            end
            
            try
                fprintf('📊 正在计算代码指标: %s\n', modelName);
                
                % 基于规则第4条：调用独立的代码指标计算工具函数
                metricsResult = computeCodeMetrics(modelName, varargin{:});
                
                result.success = true;
                result.message = metricsResult.Message;
                result.details = metricsResult;
                result.reportPath = obj.getCodeMetricsReportPath(modelName);
                
                fprintf('✅ 代码指标计算完成\n');
                if ~isempty(obj.logger)
                    obj.logger.logInfo(sprintf('代码指标计算完成: %s', modelName));
                end
                
            catch ME
                result.success = false;
                result.message = sprintf('代码指标计算失败: %s', ME.message);
                result.error = ME;
                if ~isempty(obj.logger)
                    obj.logger.logError(sprintf('代码指标计算失败 [%s]: %s', modelName, ME.message));
                end
                error('CodeAnalysisService:ComputeCodeMetricsFailed', result.message);
            end
        end
        
        %% ==================== 批量分析 ====================
        
        function results = runAllAnalysis(obj, modelName, varargin)
            % 运行所有代码分析（代码生成→检查→Polyspace→指标）
            % 输入：
            %   modelName - 模型名称
            %   varargin - 可选参数，传递给各个分析函数
            % 输出：
            %   results - 包含所有分析结果的结构体
            % 基于规则第2条和第6条：继续执行并收集所有错误，便于调试
            
            results = struct();
            results.modelName = modelName;
            results.startTime = datetime('now');
            results.analyses = struct();
            results.overallSuccess = true;
            
            if nargin < 2 || isempty(modelName)
                error('CodeAnalysisService:InvalidInput', '模型名称不能为空');
            end
            
            fprintf('🚀 正在运行所有代码分析: %s\n', modelName);
            fprintf('═══════════════════════════════════════════\n');
            
            % 1. 代码生成
            fprintf('\n[1/6] 代码生成...\n');
            try
                results.analyses.codeGeneration = obj.generateCode(modelName, varargin{:});
            catch ME
                results.analyses.codeGeneration = struct('success', false, ...
                    'message', sprintf('代码生成失败: %s', ME.message), ...
                    'error', ME);
                results.overallSuccess = false;
                fprintf('❌ 代码生成失败: %s\n', ME.message);
            end
            
            % 2. 代码检查 (Code Inspector)
            fprintf('\n[2/6] Code Inspector...\n');
            try
                results.analyses.codeInspector = obj.runCodeInspector(modelName, varargin{:});
            catch ME
                results.analyses.codeInspector = struct('success', false, ...
                    'message', sprintf('Code Inspector失败: %s', ME.message), ...
                    'error', ME);
                results.overallSuccess = false;
                fprintf('❌ Code Inspector失败: %s\n', ME.message);
            end
            
            % 3. Bug Finder
            fprintf('\n[3/6] Polyspace Bug Finder...\n');
            try
                results.analyses.bugFinder = obj.runBugFinder(modelName, varargin{:});
            catch ME
                results.analyses.bugFinder = struct('success', false, ...
                    'message', sprintf('Bug Finder失败: %s', ME.message), ...
                    'error', ME);
                results.overallSuccess = false;
                fprintf('❌ Bug Finder失败: %s\n', ME.message);
            end
            
            % 4. 编码标准检查
            fprintf('\n[4/6] 编码标准检查...\n');
            try
                results.analyses.codeStandards = obj.runCodeStandards(modelName, varargin{:});
            catch ME
                results.analyses.codeStandards = struct('success', false, ...
                    'message', sprintf('编码标准检查失败: %s', ME.message), ...
                    'error', ME);
                results.overallSuccess = false;
                fprintf('❌ 编码标准检查失败: %s\n', ME.message);
            end
            
            % 5. Code Prover
            fprintf('\n[5/6] Polyspace Code Prover...\n');
            try
                results.analyses.codeProver = obj.runCodeProver(modelName, varargin{:});
            catch ME
                results.analyses.codeProver = struct('success', false, ...
                    'message', sprintf('Code Prover失败: %s', ME.message), ...
                    'error', ME);
                results.overallSuccess = false;
                fprintf('❌ Code Prover失败: %s\n', ME.message);
            end
            
            % 6. 代码指标
            fprintf('\n[6/6] 代码指标计算...\n');
            try
                results.analyses.codeMetrics = obj.computeCodeMetrics(modelName, varargin{:});
            catch ME
                results.analyses.codeMetrics = struct('success', false, ...
                    'message', sprintf('代码指标计算失败: %s', ME.message), ...
                    'error', ME);
                results.overallSuccess = false;
                fprintf('❌ 代码指标计算失败: %s\n', ME.message);
            end
            
            results.endTime = datetime('now');
            results.duration = results.endTime - results.startTime;
            
            fprintf('\n═══════════════════════════════════════════\n');
            if results.overallSuccess
                fprintf('✅ 所有代码分析完成！\n');
            else
                fprintf('⚠️  部分分析失败，请查看详细结果\n');
            end
            fprintf('总耗时: %s\n', char(results.duration));
            
            % 打印摘要
            obj.printAnalysisSummary(results);
        end
        
        %% ==================== 报告路径获取 ====================
        
        function path = getCodeInspectorReportPath(obj, modelName)
            % 获取Code Inspector报告路径
            % 基于规则第4条：使用ProjectPathManager和ProjectNamingManager
            try
                dirPath = ProjectPathManager.getDirPath('code review', modelName);
                fileName = sprintf('%s_CodeInspector.html', modelName);
                path = fullfile(dirPath, fileName);
            catch ME
                % 基于规则第2条：明确报告错误，不使用silent fallback
                error('CodeAnalysisService:GetPathFailed', ...
                    '无法获取Code Inspector报告路径: %s', ME.message);
            end
        end
        
        function path = getBugFinderReportPath(obj, modelName)
            % 获取Bug Finder报告路径
            % 基于规则第3条：使用统一的 getRptPath 获取路径
            try
                path = getRptPath('bug finder', modelName);
            catch ME
                % 基于规则第2条：明确报告错误，不使用silent fallback
                error('CodeAnalysisService:GetPathFailed', ...
                    '无法获取Bug Finder报告路径: %s', ME.message);
            end
        end
        
        function path = getCodeStandardsReportPath(obj, modelName)
            % 获取编码标准报告路径
            % 基于规则第3条：使用统一的 getRptPath 获取路径
            try
                path = getRptPath('code standards', modelName);
            catch ME
                % 基于规则第2条：明确报告错误，不使用silent fallback
                error('CodeAnalysisService:GetPathFailed', ...
                    '无法获取编码标准报告路径: %s', ME.message);
            end
        end
        
        function path = getCodeProverReportPath(obj, modelName)
            % 获取Code Prover报告路径
            % 基于规则第3条：使用统一的 getRptPath 获取路径
            try
                path = getRptPath('code prover', modelName);
            catch ME
                % 基于规则第2条：明确报告错误，不使用silent fallback
                error('CodeAnalysisService:GetPathFailed', ...
                    '无法获取Code Prover报告路径: %s', ME.message);
            end
        end
        
        function path = getCodeMetricsReportPath(obj, modelName)
            % 获取代码指标报告路径
            % 基于规则第3条：使用统一的 getRptPath 获取路径
            try
                path = getRptPath('code metrics', modelName);
            catch ME
                % 基于规则第2条：明确报告错误，不使用silent fallback
                error('CodeAnalysisService:GetPathFailed', ...
                    '无法获取代码指标报告路径: %s', ME.message);
            end
        end
        
        function path = getPolyspaceReportPath(obj, modelName)
            % 获取Polyspace分析报告路径
            % 基于规则第4条：使用ProjectPathManager和ProjectNamingManager
            try
                dirPath = ProjectPathManager.getDirPath('code polyspace', modelName);
                fileName = ProjectNamingManager.getNameStr('polyspace report', modelName);
                path = fullfile(dirPath, [fileName, '.html']);
            catch ME
                % 基于规则第2条：明确报告错误，不使用silent fallback
                error('CodeAnalysisService:GetPathFailed', ...
                    '无法获取Polyspace报告路径: %s', ME.message);
            end
        end
        
        %% ==================== 辅助方法 ====================
        
        function printAnalysisSummary(obj, results)
            % 打印分析结果摘要
            % 输入：
            %   results - runAllAnalysis返回的结果结构体
            
            fprintf('\n📊 分析结果摘要\n');
            fprintf('═══════════════════════════════════════════\n');
            
            analysisNames = fieldnames(results.analyses);
            for i = 1:length(analysisNames)
                analysisName = analysisNames{i};
                analysisResult = results.analyses.(analysisName);
                
                % 格式化分析名称
                switch analysisName
                    case 'codeGeneration'
                        displayName = '代码生成';
                    case 'codeInspector'
                        displayName = 'Code Inspector';
                    case 'bugFinder'
                        displayName = 'Bug Finder';
                    case 'codeStandards'
                        displayName = '编码标准检查';
                    case 'codeProver'
                        displayName = 'Code Prover';
                    case 'codeMetrics'
                        displayName = '代码指标';
                    otherwise
                        displayName = analysisName;
                end
                
                % 打印结果
                if analysisResult.success
                    fprintf('  ✅ %s: 成功\n', displayName);
                else
                    fprintf('  ❌ %s: 失败\n', displayName);
                end
            end
            
            fprintf('═══════════════════════════════════════════\n');
        end
    end
end



